package com.phil.philreports.asynccelltablesearch.server.service;

import java.util.Collections;
import java.util.TreeMap;

import net.sf.jsr107cache.Cache;
import net.sf.jsr107cache.CacheException;
import net.sf.jsr107cache.CacheManager;

import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.api.datastore.DatastoreService;
import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.PreparedQuery;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.QueryResultList;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.phil.philreports.asynccelltablesearch.client.data.ClientPerson;
import com.phil.philreports.asynccelltablesearch.client.data.ClientPersons;
import com.phil.philreports.asynccelltablesearch.client.service.GetPersonsService;
import com.phil.philreports.asynccelltablesearch.server.jdo.Person;

public class GetPersonsServiceImpl extends RemoteServiceServlet
			implements GetPersonsService {

	private static final long serialVersionUID = 1L;
	
	public String generateTestData(int count) {
		Person.createTestData(count);
		return ""+count+" added";
	}

	public ClientPersons getPersons(int start, int count, String searchParam) {
		// check the search parameter
		String search = "";
		if(searchParam != null && !searchParam.trim().isEmpty()) {
			search = searchParam;
		}
		
		CursorCacher cursorCacher = new CursorCacher("Person"+search);
		try {
			cursorCacher.initCache();
		} catch (CacheException e2) {
			// TODO Auto-generated catch block
			e2.printStackTrace();
		}
		
		CachedCursor cachedCursor = null;
		try {
			cachedCursor = cursorCacher.findCursor(start);
			
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		ClientPersons persons = new ClientPersons();
		
		DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
		Query q = new Query("Person");
		
		int gap = 0;
		if(cachedCursor != null) {
			System.out.println("cachedCursor.getIndex(): " + cachedCursor.getIndex());
			gap = start-cachedCursor.getIndex();
		} else {
			gap = start;
		}
		System.out.println("gap = " + gap);
		FetchOptions fetchOptions = FetchOptions.Builder.withLimit(gap + count);
		
		// we got a cursor to work with
		if(cachedCursor != null) {
			fetchOptions.startCursor(Cursor.fromWebSafeString(cachedCursor.getCursor()));
		}
		
		// if there is a search value, add it to the query filters
		if (search != null && !search.trim().isEmpty()) {
			search = search.trim();
			System.out.println("q.addFilter(\"lastname\", Query.FilterOperator.EQUAL, "+search+");");
			q.addFilter("lastname", Query.FilterOperator.EQUAL, search);
		}
		
		PreparedQuery pq = datastore.prepare(q);
		
		QueryResultList<Entity> results = pq.asQueryResultList(fetchOptions);
		
		// get all requested results
		// consider the gap between the requested start
		// and the key found
		for(int i = gap; i < results.size(); i++) {
			System.out.println("new person " + i);
			persons.getPersons().add(new ClientPerson(
					""+results.get(i).getProperty("firstname"),
					""+results.get(i).getProperty("lastname"),
					""+results.get(i).getProperty("email")));
		}
		
		String newCursor = results.getCursor().toWebSafeString();
		
		try {
			cursorCacher.cacheCursor(new CachedCursor(start-gap+results.size(), newCursor));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return persons;
	}

}
